package com.flyiu.data.consistency.integrate;

import java.lang.reflect.Type;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flyiu.data.consistency.model.IdempotentEntity;
import com.flyiu.data.consistency.repository.IdempotentRepository;
import com.flyiu.data.idempotent.exception.IdempotentException;
import com.flyiu.data.idempotent.handler.IdempotentHandler;
import com.flyiu.data.idempotent.model.DefaultIdempotentEntity;
import com.flyiu.foundational.asserts.Assert;
import com.flyiu.foundational.util.BeanUtils;
import com.flyiu.foundational.util.ZipUtils;
import com.google.gson.Gson;

import lombok.extern.slf4j.Slf4j;

/**
 * *
 * <p>
 * 默认幂等拦截器，需自行继承IdempotentHandler，并在Idempotent.idempotentHandler中指定
 * 通过business_variables构建幂性，保存出入参的方式处理。
 * 
 * 可能存在的问题，afrerResponse
 * 
 * </p>
 * 
 * @ClassName: DefaultIempotentHandler
 * @Description: TODO
 * @author: chenjh
 * @date: 2017年11月3日 上午10:30:28
 */
@Slf4j
@Component
public class DefaultIempotentHandler extends IdempotentHandler<IdempotentEntity> {

    /** 默认幂等性属性保存Mapper */
    @Autowired
    private IdempotentRepository idempotentRepository;

    /** 使用GSON，可处理泛型问题 */
    private static final Gson    gson       = new Gson();

    private static final String  SPLIT_CHAR = "X@X";
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 对象转Json String
     * 
     * @param arg
     * @return
     */
    private String toJson(Object arg) {
        if (arg != null) {
            String context = "";
            try {
                context = objectMapper.writeValueAsString(arg);
            } catch (JsonProcessingException e) {
                log.error("", e);
            }
            return context;
        }
        return "";
    }

    /**
     * 对象数组转Json串，对象中以 SPLIT_CHAR 分割
     * 
     * @param args
     * @return
     */
    private static String toJson(Object[] args) {
        if (args != null) {
            StringBuffer context = new StringBuffer();
            for (Object arg : args) {
                context.append(gson.toJson(arg, arg.getClass()) + SPLIT_CHAR);
            }
            return context.toString();
        }
        return "";
    }

    @Override
    protected Object before(Object[] args, String hashCode) {
        // IdempotentEntity idempotentEntity = new IdempotentEntity();
        // // idempotentEntity.setContext(toJson(args));
        // idempotentEntity.setHash(hashCode);
        // idempotentEntity.setIdemValue(idemValuesThreadLocal.get());
        // idempotentRepository.save(idempotentEntity);
        // idempotentEntityThreadLocal.set(idempotentEntity);
        // return idempotentEntity;
        return null;
    }



    @Override
    protected void afterResponse(Object responseObj) {
        if (idempotentEntityThreadLocal.get() != null) {
            IdempotentEntity idempotentEntity = idempotentEntityThreadLocal.get();
            log.error("我已经开始执行了");
            idempotentRepository.updateIdempotent("COMMIT", ZipUtils.compress(toJson(responseObj)), idempotentEntity.getId());
            log.error("我已经执行了");
        }
        super.afterResponse(responseObj);
    }

    @Override
    protected Object buildDuplicateResponse(DefaultIdempotentEntity idempotentEntity, Type reponseType) {
        IdempotentEntity recod = idempotentRepository.findByIdemValue(idempotentEntity.getKey());
        if (recod != null) {
            Assert.assertNotTrue(() -> new IdempotentException("010005001100", "请求正在处理中,请稍候重试"), StringUtils.equals(recod.getState(), "I"));
            Assert.assertEquals(() -> new IdempotentException("010004031100", "请求已存在,且当次请求与之前参数不匹配"), idempotentEntity.getHash(), recod.getHash());
            Assert.assertNotTrue(() -> new IdempotentException("010005001101", "幂等失败，请检查业务结果"), StringUtils.isEmpty(recod.getResponse()));
            return gson.fromJson(recod.getUnCompressResponse(), reponseType);
        }
        return null;
    }
    
    

    /** 
     * @see com.flyiu.data.idempotent.handler.IdempotentHandler#failure(java.lang.Object, java.lang.Exception, org.aspectj.lang.ProceedingJoinPoint)
     */
    @Override
    protected void failure(Object beforeObj, Exception e, ProceedingJoinPoint joinPoint) {
        if (idempotentEntityThreadLocal.get() != null) {
            IdempotentEntity idempotentEntity = idempotentEntityThreadLocal.get();
            idempotentRepository.delete(idempotentEntity);
        }
    }

    @Override
    public boolean tryAcquire(DefaultIdempotentEntity idempotentEntity) {
        try {
            IdempotentEntity disIdempotentEntity = BeanUtils.toNewType(idempotentEntity, IdempotentEntity.class);
            disIdempotentEntity.setIdemValue(idempotentEntity.getKey());
            disIdempotentEntity.setCreateDate(new Date());
            idempotentRepository.save(disIdempotentEntity);
            idempotentEntityThreadLocal.set(disIdempotentEntity);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
